home *** CD-ROM | disk | FTP | other *** search
/ Meeting Pearls 4 / Meeting Pearls Vol. IV (1996)(GTI - Schatztruhe)[!].iso / Pearls / gfx / Viewer / CyberAnim / source.lha / CyberAnim.c next >
C/C++ Source or Header  |  1996-09-08  |  46KB  |  1,521 lines

  1. /*****************************************************************************
  2.  
  3.         Cybergraphics Animation Viewer v1.0          8 Sep 1996
  4.         -----------------------------------
  5.  
  6. The files in this archive may be distributed anywhere provided they are
  7. unmodified and are not sold for profit.
  8.  
  9. Ownership and copyright of all files remains with the author:
  10.  
  11.     Peter McGavin, 86 Totara Crescent, Lower Hutt, New Zealand.
  12.     e-mail: peterm@maths.grace.cri.nz
  13.  
  14. *****************************************************************************/
  15.  
  16. #include "CyberAnim.h"  /* separate file for GST */
  17.  
  18. #include "unpack.h"
  19. #include "math64.h"
  20.  
  21. #define WIDTH    320
  22. #define HEIGHT   240
  23. #define DEPTH      8
  24.  
  25. #define NBITMAPS   2
  26.  
  27. /****************************************************************************/
  28.  
  29. #ifdef __SASC
  30. const char version[] = "$VER: CyberAnim 1.0 " __AMIGADATE__ ;
  31. long __oslibversion = 38;    /* we require at least OS3.0 */
  32. char __stdiowin[] = "CON:20/50/500/130/CyberAnim";
  33. char __stdiov37[] = "/AUTO/CLOSE";
  34. #endif
  35.  
  36. #ifndef max
  37. #define max(x,y) ((x)>=(y))?(x):(y)
  38. #endif
  39.  
  40. char programname[20];
  41. BPTR olddir = NULL;
  42. struct RDArgs *rdargs = NULL;
  43.  
  44. /****************************************************************************/
  45.  
  46. #define ID_ANIM MAKE_ID('A','N','I','M')
  47. #define ID_ILBM MAKE_ID('I','L','B','M')
  48. #define ID_ANHD MAKE_ID('A','N','H','D')
  49. #define ID_BMHD MAKE_ID('B','M','H','D')
  50. #define ID_CMAP MAKE_ID('C','M','A','P')
  51. #define ID_CAMG MAKE_ID('C','A','M','G')
  52. #define ID_BODY MAKE_ID('B','O','D','Y')
  53. #define ID_DLTA MAKE_ID('D','L','T','A')
  54.  
  55. /*  Masking techniques    */
  56. #define    mskNone            0
  57. #define    mskHasMask        1
  58. #define    mskHasTransparentColor    2
  59. #define    mskLasso        3
  60. #define    mskHasAlpha        4
  61.  
  62. /*  Compression techniques  */
  63. #define    cmpNone            0
  64. #define    cmpByteRun1        1
  65. #define    cmpByteRun2        2
  66.  
  67. /*  Bitmap header (BMHD) structure  */
  68. struct BitMapHeader
  69. {
  70.   UWORD bmh_Width;        /* Width in pixels */
  71.   UWORD bmh_Height;        /* Height in pixels */
  72.   WORD  bmh_Left;        /* Left position */
  73.   WORD  bmh_Top;        /* Top position */
  74.   UBYTE bmh_Depth;        /* Number of planes */
  75.   UBYTE bmh_Masking;        /* Masking type */
  76.   UBYTE bmh_Compression;    /* Compression type */
  77.   UBYTE bmh_Pad;
  78.   UWORD bmh_Transparent;    /* Transparent color */
  79.   UBYTE bmh_XAspect;
  80.   UBYTE bmh_YAspect;
  81.   WORD  bmh_PageWidth;
  82.   WORD  bmh_PageHeight;
  83. };
  84.  
  85. /*  Animation compression modes  */
  86. #define cmpDirect        0
  87. #define cmpXor            1
  88. #define cmpLongdelta        2
  89. #define cmpShortdelta        3
  90. #define cmpDelta        4
  91. #define cmpBytedelta        5
  92. #define cmpStereo        6
  93. #define cmpAnim7        7
  94. #define cmpJ            74
  95.  
  96. /*  Animation header flags  */
  97. #define anfLongdata    (1<<0)
  98. #define anfXor        (1<<1)
  99. #define anfOnelist    (1<<2)
  100. #define anfRLC        (1<<3)
  101. #define anfVertical    (1<<4)
  102. #define anfLongoffsets    (1<<5)
  103.  
  104. /*  Animation header (ANHD) structure  */
  105. struct AnimHeader
  106. {
  107.   UBYTE anh_Operation;        /* Compression method */
  108.   UBYTE anh_Mask;        /* plane mask (xor mode only) */
  109.   UWORD anh_W, anh_H;        /* w & h of body (xor mode only) */
  110.   WORD  anh_X, anh_Y;        /* offset of body (xor mode only) */
  111.   ULONG anh_Abstime;        /* 1/60s sec relative to 1st frame */
  112.   ULONG anh_Reltime;        /* 1/60s sec relative to prev frame */
  113.   UBYTE anh_Interleave;        /* Modify frame this many back (0=2) */
  114.   UBYTE anh_Pad0;
  115.   ULONG anh_Bits;        /* animation header flags */
  116.   UBYTE anh_Pad[16];
  117. };
  118.  
  119. struct mystream {
  120.   FILE *f;
  121.   UBYTE *rambuf;
  122.   UBYTE *rambufptr;
  123.   ULONG rambufsize;
  124. };
  125.  
  126. struct options {
  127.   BOOL ram;
  128.   BOOL once;
  129.   BOOL dbuf;
  130.   BOOL warp;
  131.   BOOL modereq;
  132.   BOOL waittof;
  133. };
  134.  
  135. /****************************************************************************/
  136.  
  137. struct Library *CyberGfxBase = NULL;
  138.  
  139. static struct Rectangle rect;
  140.  
  141. static struct TagItem ti[] =
  142.   {{SA_DisplayID, 0x40420000},
  143.    {SA_DClip, (ULONG)&rect},
  144.    {TAG_DONE, 0}};
  145.  
  146. static struct Screen *s = NULL;
  147. static struct ExtNewScreen ns = {
  148.   0, 0, WIDTH, HEIGHT, DEPTH,
  149.   2, 1,
  150.   HIRES | LACE,
  151.   CUSTOMSCREEN | NS_EXTENDED,
  152.   NULL,
  153.   NULL,
  154.   NULL,
  155.   NULL,
  156.   &ti[0]
  157. };
  158.  
  159. static struct Window *w = NULL;
  160. static struct NewWindow nw = {
  161.   0,0,            /* Starting corner */
  162.   WIDTH,HEIGHT,        /* Width, height */
  163.   2,1,            /* detail, block pens */
  164.   IDCMP_VANILLAKEY | IDCMP_RAWKEY | IDCMP_MOUSEBUTTONS, /* IDCMP flags */
  165.   WFLG_ACTIVATE | WFLG_BORDERLESS | WFLG_RMBTRAP,    /* Window flags */
  166.   NULL,            /* Pointer to first gadget */
  167.   NULL,            /* Pointer to checkmark */
  168.   NULL,            /* title */
  169.   NULL,            /* screen pointer */
  170.   NULL,            /* bitmap pointer */
  171.   0,0,0,0,        /* window not sized */
  172.   CUSTOMSCREEN        /* type of screen */
  173. };
  174.  
  175. static struct BitMap *bm[NBITMAPS] = {NBITMAPS * NULL};
  176. static BOOL using_fastmem_bitmap = FALSE;
  177. static BOOL using_intermediate_buffer = FALSE;
  178. static WORD *dirty = NULL;
  179.  
  180. static struct IFFHandle *iff = NULL;
  181. static BOOL iff_is_open = FALSE;
  182.  
  183. static UWORD *emptypointer = NULL;
  184.  
  185. static struct FileRequester *fr = NULL;
  186. static struct ScreenModeRequester *smr = NULL;
  187.  
  188. struct Library *TimerBase = NULL;
  189. struct MsgPort *timermp = NULL;
  190. struct timerequest *timerio = NULL;
  191. ULONG timerclosed = TRUE;
  192. struct EClockVal *time = NULL;
  193. struct EClockVal *time0 = NULL;
  194. struct EClockVal *time1 = NULL;
  195. double micros_per_eclock;    /* Length of EClock tick in microseconds */
  196.  
  197. /****************************************************************************/
  198.  
  199. static void partial_cleanup (void)
  200. {
  201.   int i, plane;
  202.  
  203.   if (iff_is_open) {
  204.     CloseIFF (iff);
  205.     iff_is_open = FALSE;
  206.   }
  207.   if (iff != NULL) {
  208.     if (iff->iff_Stream != NULL) {
  209.       if (((struct mystream *)iff->iff_Stream)->f != NULL)
  210.         fclose (((struct mystream *)iff->iff_Stream)->f);
  211.       if (((struct mystream *)iff->iff_Stream)->rambuf != NULL)
  212.         free (((struct mystream *)iff->iff_Stream)->rambuf);
  213.       free ((void *)iff->iff_Stream);
  214.     }
  215.     FreeIFF (iff);
  216.     iff = NULL;
  217.   }
  218.   for (i = 0; i < NBITMAPS; i++) {
  219.     if (!using_intermediate_buffer) {
  220.       if (bm[i] != NULL)
  221.         free (bm[i]);
  222.     } else if (using_fastmem_bitmap) {
  223.       if (bm[i] != NULL) {
  224.         for (plane = 0; plane < bm[i]->Depth; plane++)
  225.           if (bm[i]->Planes[plane] != NULL)
  226.             free (bm[i]->Planes[plane]);
  227.         free (bm[i]);
  228.       }
  229.     } else
  230.       FreeBitMap (bm[i]);
  231.     bm[i] = NULL;
  232.   }
  233.   if (dirty != NULL) {
  234.     free (dirty);
  235.     dirty = NULL;
  236.   }
  237.   if (w != NULL) {
  238.     CloseWindow (w);
  239.     w = NULL;
  240.   }
  241.   if (s != NULL) {
  242.     CloseScreen (s);
  243.     s = NULL;
  244.   }
  245.   if (emptypointer != NULL) {
  246.     FreeMem (emptypointer, 12);
  247.     emptypointer = NULL;
  248.   }
  249. }
  250.  
  251. /****************************************************************************/
  252.  
  253. static void cleanup (void)
  254. {
  255.   partial_cleanup ();
  256.   if (IFFParseBase != NULL) {
  257.     CloseLibrary ((struct Library *)IFFParseBase);
  258.     IFFParseBase = NULL;
  259.   }
  260.   if (olddir != NULL) {
  261.     CurrentDir (olddir);
  262.     olddir = NULL;
  263.   }
  264.   if (rdargs != NULL) {
  265.     FreeArgs (rdargs);
  266.     rdargs = NULL;
  267.   }
  268.   if (time1 != NULL) {
  269.     FreeMem (time1, sizeof(struct EClockVal));
  270.     time1 = NULL;
  271.   }
  272.   if (time0 != NULL) {
  273.     FreeMem (time0, sizeof(struct EClockVal));
  274.     time0 = NULL;
  275.   }
  276.   if (time != NULL) {
  277.     FreeMem (time, sizeof(struct EClockVal));
  278.     time = NULL;
  279.   }
  280.   if (!timerclosed) {
  281.     CloseDevice ((struct IORequest *)timerio);
  282.     timerclosed = TRUE;
  283.     TimerBase = NULL;
  284.   }
  285.   if (timerio != NULL) {
  286.     DeleteExtIO ((struct IORequest *)timerio);
  287.     timerio = NULL;
  288.   }
  289.   if (timermp != NULL) {
  290.     DeletePort (timermp);
  291.     timermp = NULL;
  292.   }
  293.   if (smr != NULL) {
  294.     FreeAslRequest (smr);
  295.     smr = NULL;
  296.   }
  297.   if (fr != NULL) {
  298.     FreeAslRequest (fr);
  299.     fr = NULL;
  300.   }
  301.   if (AslBase != NULL) {
  302.     CloseLibrary ((struct Library *)AslBase);
  303.     AslBase = NULL;
  304.   }
  305.   if (CyberGfxBase != NULL) {
  306.     CloseLibrary ((struct Library *)CyberGfxBase);
  307.     CyberGfxBase = NULL;
  308.   }
  309. }
  310.  
  311. #ifdef __SASC
  312. void _CXBRK (void)
  313. {
  314.   cleanup ();
  315.   fprintf (stderr, "**Break\n");
  316.   exit (0);
  317. }
  318. #endif
  319.  
  320. /****************************************************************************/
  321.  
  322. static char bodystring[64];
  323.  
  324. static struct TextAttr topaz80 = {
  325.   "topaz.font", 8, 0, 0
  326. };
  327.  
  328. static struct IntuiText bodytext[] = {
  329.   {0, 1, JAM2, 10, 8, &topaz80, programname, &bodytext[1]},
  330.   {0, 1, JAM2, 10, 20, &topaz80, bodystring, NULL},
  331. };
  332.  
  333. static struct IntuiText negtext = {0, 1, JAM2, 6, 3, &topaz80, "Ok", NULL};
  334.  
  335. static void die (char *msg, ...)
  336. /* Exit program with message, return code 10 */
  337. {
  338.   va_list arglist;
  339.  
  340.   cleanup ();
  341.   va_start (arglist, msg);
  342.   vsprintf (bodystring, msg, arglist);
  343.   va_end (arglist);
  344.   AutoRequest (w, &bodytext[0], NULL, &negtext, 0, 0, 320, 60);
  345.   exit (10);
  346. }
  347.  
  348. /****************************************************************************/
  349.  
  350. static void *malloc_check (size_t size)
  351. {
  352.   void *p;
  353.  
  354.   if ((p = malloc (size)) == NULL)
  355.     die ("%s: Out of memory trying to allocate %ld bytes!", programname,
  356.          size);
  357.   return (p);
  358. }
  359.  
  360. /****************************************************************************/
  361.  
  362. static void delay_until (struct EClockVal *next_time)
  363. {
  364.   ReadEClock (time);
  365.   if (cmp64 (time, next_time) > 0) {
  366.     timerio->tr_node.io_Command = TR_ADDREQUEST;
  367.     *(struct EClockVal *)&timerio->tr_time = *next_time;
  368.     sub64 ((struct EClockVal *)&timerio->tr_time, time); /* timerio->tr_time -= time */
  369.     /* oldpri = SetTaskPri (thistask, 20); */ /* don't flicker when mouse moves */
  370.     DoIO ((struct IORequest *)timerio);  /* delay */
  371.     /* SetTaskPri (thistask, oldpri); */ /* restore task priority */
  372.   }
  373.   while (cmp64 (time, next_time) > 0)
  374.     ReadEClock (time);
  375.   *next_time = *time;
  376. }
  377.  
  378. /****************************************************************************/
  379.  
  380. static void parse_tooltypes (char *fname, struct options *opt)
  381. {
  382.   struct DiskObject *obj;
  383.   char **toolarray;
  384.  
  385.   if ((obj = GetDiskObject (fname)) != NULL) {
  386.     toolarray = obj->do_ToolTypes;
  387.     if (FindToolType (toolarray, "DISK") != NULL)
  388.       opt->ram = FALSE;
  389.     if (FindToolType (toolarray, "RAM") != NULL)
  390.       opt->ram = FALSE;
  391.     if (FindToolType (toolarray, "ONCE") != NULL)
  392.       opt->once = TRUE;
  393.     if (FindToolType (toolarray, "WARP") != NULL)
  394.       opt->warp = TRUE;
  395.     if (FindToolType (toolarray, "NOMODEREQ") != NULL)
  396.       opt->modereq = FALSE;
  397.     if (FindToolType (toolarray, "WAITTOF") != NULL)
  398.       opt->waittof = TRUE;
  399.     FreeDiskObject (obj);
  400.   }
  401. }
  402.  
  403. /****************************************************************************/
  404.  
  405. static void load_cmap (struct Screen *s, UBYTE *cmap, int ncolours,
  406.                        ULONG intended_mode)
  407. {
  408.   int c;
  409.   ULONG *colourtable;
  410.  
  411.   colourtable = (ULONG *)malloc_check ((1 + 3 * ncolours + 1) * sizeof(ULONG));
  412.   colourtable[0] = (ncolours << 16) + 0;
  413.   for (c = 0; c < ncolours; c++) {
  414.     colourtable[3 * c + 1] = *cmap++ * 0x01010101;
  415.     colourtable[3 * c + 2] = *cmap++ * 0x01010101;
  416.     colourtable[3 * c + 3] = *cmap++ * 0x01010101;
  417.   }
  418.   if ((intended_mode & EXTRAHALFBRITE_KEY) != 0) {
  419.     cmap -= 3 * ncolours;
  420.     for (c = ncolours >> 1; c < ncolours; c++) {
  421.       colourtable[3 * c + 1] = (cmap[0] >> 1) * 0x01010101;
  422.       colourtable[3 * c + 2] = (cmap[1] >> 1) * 0x01010101;
  423.       colourtable[3 * c + 3] = (cmap[2] >> 1) * 0x01010101;
  424.       cmap += 3;
  425.     }
  426.   }
  427.   colourtable[1 + 3 * ncolours] = 0;
  428.   LoadRGB32 (&s->ViewPort, colourtable);
  429.   free (colourtable);
  430. }
  431.  
  432. /****************************************************************************/
  433.  
  434. static BOOL unpackrow (BYTE **src0, BYTE *dst, WORD dstbytes)
  435. {
  436.   BYTE *src;
  437.   BYTE n;
  438.   BOOL err;
  439.  
  440.   err = TRUE;
  441.   src = *src0;
  442.   while (dstbytes > 0) {
  443.     n = *src++;
  444.     if (n >= 0) {
  445.       n += 1;
  446.       if ((dstbytes -= n) < 0)
  447.         goto error;
  448.       memcpy (dst, src, n);
  449.       src += n;
  450.     } else if (n != -128) {
  451.       n = 1 - n;
  452.       if ((dstbytes -= n) < 0)
  453.         goto error;
  454.       memset (dst, *src++, n);
  455.     }
  456.     dst += n;
  457.   }
  458.   err = FALSE;
  459. error:
  460.   *src0 = src;
  461.   return (err);
  462. }
  463.  
  464. /****************************************************************************/
  465.  
  466. static void unpacklongdelta (WORD *wdata, LONG *plane, WORD bytesperrow,
  467.                              WORD *dirty)
  468. {
  469.   WORD offset, count;
  470.  
  471.   while ((offset = *wdata++) != -1) {
  472.     if (offset >= 0) {
  473.       plane += offset;
  474.       *plane = *(LONG *)wdata;
  475.       wdata += 2;
  476.     } else {
  477.       count = *wdata++;
  478.       plane += -offset - 1;
  479.       memcpy (plane, wdata, count << 2);
  480.       plane += count - 1;
  481.       wdata += (count << 1);
  482.     }
  483.   }
  484. }
  485.  
  486. /****************************************************************************/
  487.  
  488. static void unpackshortdelta (WORD *wdata, WORD *plane, WORD bytesperrow,
  489.                               WORD *dirty)
  490. {
  491.   WORD offset, count;
  492.  
  493.   while ((offset = *wdata++) != -1) {
  494.     if (offset >= 0) {
  495.       plane += offset;
  496.       *plane = *wdata++;
  497.     } else {
  498. /*
  499.       plane += -offset - 1;
  500.       for (count = *wdata++; count > 0; count--)
  501.         *plane++ = *wdata++;
  502.       plane--;
  503. */
  504.       count = *wdata++;
  505.       plane += -offset - 1;
  506.       memcpy (plane, wdata, count << 1);
  507.       plane += count - 1;
  508.       wdata += count;
  509.     }
  510.   }
  511. }
  512.  
  513. /****************************************************************************/
  514.  
  515. #if 0
  516. void __asm unpackbytedelta (register __a0 BYTE *bdata,
  517.                             register __a1 PLANEPTR plane,
  518.                             register __d0 WORD bytesperrow,
  519.                             register __a2 WORD *dirty);
  520.  
  521. static void unpackbytedelta (BYTE *bdata, PLANEPTR plane, WORD bytesperrow,
  522.                              WORD *dirty)
  523. {
  524.   WORD x, y, count, w, first, last;
  525.   BYTE *bp;
  526.   UBYTE ub;
  527.  
  528.   for (x = 0; x < bytesperrow; x++) {
  529.     first = -1;
  530.     last = -1;
  531.     bp = &plane[x];
  532.     y = 0;
  533.     for (count = *bdata++; count > 0; count--) {
  534.       if ((w = *bdata++) > 0) {
  535.         y += w;
  536.         bp += w * bytesperrow;
  537.       } else if (w < 0) {
  538.         if (first < 0)
  539.           first = y;
  540.         last = (y += (w &= 0x7f));
  541.         for ( ; w > 0; w--) {
  542.           *bp = *bdata++;
  543.           bp += bytesperrow;
  544.         }
  545.       } else /* w == 0 */ {
  546.         if (first < 0)
  547.           first = y;
  548.         last = (y += (ub = (UBYTE)*bdata++));
  549.         w = *bdata++;
  550.         for ( ; ub > 0; ub--) {
  551.           *bp = w;
  552.           bp += bytesperrow;
  553.         }
  554.       }
  555.     }
  556.     if (first >= 0 && (dirty[0] < 0 || first < dirty[0]))
  557.       dirty[0] = first;
  558.     if (last >= 0 && (dirty[1] < 0 || last > dirty[1]))
  559.       dirty[1] = last;
  560.     if ((x & 3) == 3)
  561.       dirty += 2;
  562.   }
  563. }
  564. #endif
  565.  
  566. /****************************************************************************/
  567.  
  568. static void unpackanim7word (BYTE *bdata, WORD *data, PLANEPTR plane,
  569.                              WORD wordsperrow, WORD *dirty)
  570. {
  571.   WORD x, y, count, w, first, last;
  572.   WORD *wp;
  573.   UBYTE ub;
  574.  
  575.   for (x = 0; x < wordsperrow; x++) {
  576.     first = -1;
  577.     last = -1;
  578.     wp = &((WORD *)plane)[x];
  579.     y = 0;
  580.     for (count = *bdata++; count > 0; count--) {
  581.       if ((w = *bdata++) > 0) {
  582.         y += w;
  583.         wp += w * wordsperrow;
  584.       } else if (w < 0) {
  585.         if (first < 0)
  586.           first = y;
  587.         last = (y += (w &= 0x7f));
  588.         for ( ; w > 0; w--) {
  589.           *wp = *data++;
  590.           wp += wordsperrow;
  591.         }
  592.       } else /* w == 0 */ {
  593.         if (first < 0)
  594.           first = y;
  595.         last = (y += (ub = (UBYTE)*bdata++));
  596.         w = *data++;
  597.         for ( ; ub > 0; ub--) {
  598.           *wp = w;
  599.           wp += wordsperrow;
  600.         }
  601.       }
  602.     }
  603.     if (first >= 0 && (dirty[0] < 0 || first < dirty[0]))
  604.       dirty[0] = first;
  605.     if (last >= 0 && (dirty[1] < 0 || last > dirty[1]))
  606.       dirty[1] = last;
  607.     if ((x & 1) == 1)
  608.       dirty += 2;
  609.   }
  610. }
  611.  
  612. /****************************************************************************/
  613.  
  614. #if 0
  615. void __asm unpackanim7long (register __a0 BYTE *bdata,
  616.                             register __a4 LONG *data,
  617.                             register __a1 PLANEPTR plane,
  618.                             register __d0 WORD bytesperrow,
  619.                             register __a2 WORD *dirty);
  620.  
  621. static void unpackanim7long (BYTE *bdata, LONG *data, PLANEPTR plane,
  622.                              WORD bytesperrow, WORD *dirty)
  623. {
  624.   WORD x, y, count, w, first, last;
  625.   LONG *lp, l;
  626.   UBYTE ub;
  627.  
  628.   for (x = 0; x < bytesperrow; x += 4) {
  629.     first = -1;
  630.     last = -1;
  631.     lp = &((LONG *)plane)[x];
  632.     y = 0;
  633.     for (count = *bdata++; count > 0; count--) {
  634.       if ((w = *bdata++) > 0) {
  635.         y += w;
  636.         lp += w * (bytesperrow >> 2);
  637.       } else if (w < 0) {
  638.         if (first < 0)
  639.           first = y;
  640.         last = (y += (w &= 0x7f));
  641.         for ( ; w > 0; w--) {
  642.           *lp = *data++;
  643.           lp += (bytesperrow >> 2);
  644.         }
  645.       } else /* w == 0 */ {
  646.         if (first < 0)
  647.           first = y;
  648.         last = (y += (ub = (UBYTE)*bdata++));
  649.         l = *data++;
  650.         for ( ; ub > 0; ub--) {
  651.           *lp = l;
  652.           lp += (bytesperrow >> 2);
  653.         }
  654.       }
  655.     }
  656.     if (first >= 0 && (dirty[0] < 0 || first < dirty[0]))
  657.       dirty[0] = first;
  658.     if (last >= 0 && (dirty[1] < 0 || last > dirty[1]))
  659.       dirty[1] = last;
  660.     dirty += 2;
  661.   }
  662. }
  663. #endif
  664.  
  665. /****************************************************************************/
  666.  
  667. static void blit_opt (struct BitMap *bm, struct RastPort *rp, WORD *dirty,
  668.                       int yoffset)
  669. {
  670.   WORD x, firstx, miny, maxy;
  671.  
  672.   firstx = -1;
  673.   for (x = 0; x < bm->BytesPerRow; x += 4) {
  674.     if (dirty[0] >= 0 && dirty[1] >= 0) {
  675.       if (firstx == -1) {
  676.         firstx = x;
  677.         miny = dirty[0];
  678.         maxy = dirty[1];
  679.       } else if (abs(dirty[0] - miny) < 10 &&
  680.                  abs(dirty[1] - maxy) < 10) {
  681.         miny = min(dirty[0], miny);
  682.         maxy = max(dirty[1], maxy);
  683.       } else {
  684.         BltBitMapRastPort (bm, firstx << 3, miny, rp, firstx << 3,
  685.                            miny + yoffset, (x - firstx) << 3,
  686.                            maxy - miny, 0xc0);
  687.         firstx = x;
  688.         miny = dirty[0];
  689.         maxy = dirty[1];
  690.       }
  691.     } else if (firstx != -1) {
  692.       BltBitMapRastPort (bm, firstx << 3, miny, rp, firstx << 3,
  693.                          miny + yoffset, (x - firstx) << 3,
  694.                          maxy - miny, 0xc0);
  695.       firstx = -1;
  696.     }
  697.     dirty += 2;
  698.   }
  699.   if (firstx != -1)
  700.     BltBitMapRastPort (bm, firstx << 3, miny, rp, firstx << 3,
  701.                        miny + yoffset, (bm->BytesPerRow - firstx) << 3,
  702.                        maxy - miny, 0xc0);
  703. }
  704.  
  705. /****************************************************************************/
  706.  
  707. #if 0
  708. static void PrintTopChunk (struct IFFHandle *iff)
  709. {
  710.   struct ContextNode *top;
  711.   short i;
  712.   char idbuf[5];
  713.  
  714.   /* Get a pointer to the context node describing the current context. */
  715.   if (!(top = CurrentChunk (iff)))
  716.         return;
  717.  
  718.   /*
  719.    * Print a series of dots equivalent to the current nesting depth of chunks processed so far.
  720.    * This will cause nested chunks to be printed out indented.
  721.    */
  722.   for (i = iff->iff_Depth;  i--; )
  723.     printf (". ");
  724.  
  725.   /* Print out the current chunk's ID and size. */
  726.   printf ("%s %ld ", IDtoStr (top->cn_ID, idbuf), top->cn_Size);
  727.  
  728.   /* Print the current chunk's type, with a newline. */
  729.   puts (IDtoStr (top->cn_Type, idbuf));
  730. }
  731. #endif
  732.  
  733. /****************************************************************************/
  734.  
  735. #ifdef __SASC
  736. static __saveds __asm LONG mystreamhandler (
  737.   register __a0 struct Hook *hook,
  738.   register __a2 struct IFFHandle *iff,
  739.   register __a1 struct IFFStreamCmd *actionpkt)
  740. {
  741. #else /* gcc */
  742. static LONG mystreamhandler (void)
  743. {
  744.   register struct Hook *hook __asm("a0");
  745.   register struct IFFHandle *iff __asm("a2");
  746.   register struct IFFStreamCmd *actionpkt __asm("a1");
  747. #endif
  748.   struct mystream *s;
  749.   LONG nbytes, error;
  750.   UBYTE *buf;
  751.  
  752.   s = (struct mystream *)iff->iff_Stream;
  753.   nbytes = actionpkt->sc_NBytes;
  754.   buf = (UBYTE *)actionpkt->sc_Buf;
  755.   switch (actionpkt->sc_Command) {
  756.     case IFFCMD_READ:
  757.       if (s->f != NULL)
  758.         error = (fread (buf, 1, nbytes, s->f) != nbytes);
  759.       else if (s->rambuf != NULL &&
  760.                nbytes <= s->rambuf + s->rambufsize - s->rambufptr &&
  761.                nbytes >= 0) {
  762.         /* printf ("Reading %d from %d\n", nbytes, s->rambufptr - s->rambuf); */
  763.         if (nbytes > 0) {
  764.           memcpy (buf, s->rambufptr, nbytes);
  765.           s->rambufptr += nbytes;
  766.         }
  767.         error = FALSE;
  768.       } else
  769.         error = TRUE;
  770.       break;
  771.     case IFFCMD_WRITE:
  772.       if (s->f != NULL)
  773.         error = (fwrite (buf, 1, nbytes, s->f) != nbytes);
  774.       else
  775.         error = TRUE;
  776.       break;
  777.     case IFFCMD_SEEK:
  778.       if (s->f != NULL)
  779.         error = (fseek (s->f, nbytes, SEEK_CUR) == -1);
  780.       else if (s->rambuf != NULL) {
  781.         s->rambufptr += nbytes;
  782.         error = s->rambufptr > (s->rambuf + s->rambufsize) ||
  783.                 s->rambufptr < s->rambuf;
  784.       } else
  785.         error = TRUE;
  786.       break;
  787.     case IFFCMD_INIT:
  788.     case IFFCMD_CLEANUP:
  789.       error = FALSE;
  790.       break;
  791.     default:
  792.       error = TRUE;
  793.   }
  794.   return (error);
  795. }
  796.  
  797. static struct Hook mystreamhook = {
  798.   {NULL},
  799.   (ULONG (*)())mystreamhandler,
  800.   NULL,
  801.   NULL
  802. };
  803.  
  804. /****************************************************************************/
  805.  
  806. static void animate_file (char *fname, struct options opt)
  807. {
  808.   int plane, /* x, */ y, i, width, height, oscan_height, depth, which, ifferror;
  809.   ULONG class, size, intended_mode, totalframes, sig;
  810.   UWORD code, count, propertymask, srcbytesperrow;
  811.   WORD *wdata;
  812.   UBYTE *body, *src, *dst[8], *dlta;
  813.   LONG fsize;
  814.   struct IntuiMessage *msg;
  815.   BOOL going, first_time;
  816.   struct StoredProperty *bmhdprop, *cmapprop, *camgprop, *anhdprop;
  817.   struct BitMapHeader *bmhd;
  818.   struct AnimHeader *anhd;
  819.   struct DimensionInfo dimsinfo;
  820.   struct mystream *mystream;
  821.   char reqtitle[30], *type_string;
  822.   struct EClockVal eclocks, warp_eclocks, total_eclocks, next_time;
  823.  
  824.  
  825.   parse_tooltypes (fname, &opt);
  826.  
  827.   if ((iff = AllocIFF ()) == NULL)
  828.     die ("%s: AllocIFF() failed", programname);
  829.  
  830.   mystream = (struct mystream *)malloc_check (sizeof(struct mystream));
  831.   memset (mystream, 0, sizeof(struct mystream));
  832.  
  833.   if ((mystream->f = fopen (fname, "r")) == 0)
  834.     die ("%s: Can't open %s", programname, fname);
  835.   if (fseek (mystream->f, 0, SEEK_END) == -1 ||
  836.       (fsize = ftell (mystream->f)) == -1)
  837.     die ("%s: Error seeking %s", programname, fname);
  838.   rewind (mystream->f);
  839.  
  840.   if (opt.ram && (mystream->rambuf = malloc (fsize)) != NULL) {
  841.     if (fread (mystream->rambuf, 1, fsize, mystream->f) != fsize ||
  842.         fclose (mystream->f) == EOF)
  843.       die ("%s: Error reading %s", programname, fname);
  844.     mystream->f = NULL;
  845.     mystream->rambufptr = mystream->rambuf;
  846.     mystream->rambufsize = fsize;
  847.   } else {
  848.     if (opt.ram)
  849.       printf ("Not enough memory to play from RAM, playing from DISK instead\n");
  850.     mystream->rambuf = NULL;
  851.   }
  852.  
  853.   iff->iff_Stream = (ULONG)mystream;
  854.   InitIFF (iff, IFFF_FSEEK | IFFF_RSEEK, &mystreamhook);
  855.  
  856.   if (OpenIFF (iff, IFFF_READ) != 0)
  857.     die ("%s: OpenIFF() failed", programname);
  858.   iff_is_open = TRUE;
  859.  
  860.   if (PropChunk (iff, ID_ILBM, ID_BMHD) != 0 ||
  861.       PropChunk (iff, ID_ILBM, ID_ANHD) != 0 ||
  862.       PropChunk (iff, ID_ILBM, ID_CMAP) != 0 ||
  863.       PropChunk (iff, ID_ILBM, ID_CAMG) != 0 ||
  864.       StopChunk (iff, ID_ILBM, ID_BODY) != 0)
  865.     die ("%s: Error calling PropChunk or StopChunk parsing %s", programname, fname);
  866.   if ((ifferror = ParseIFF (iff, IFFPARSE_SCAN)) != 0) {
  867.     fprintf (stderr, "%s: IFF error %d parsing %s\n", programname, ifferror, fname);
  868.     partial_cleanup ();
  869.     return;
  870.   }
  871.   if ((bmhdprop = FindProp (iff, ID_ILBM, ID_BMHD)) == NULL ||
  872.       (cmapprop = FindProp (iff, ID_ILBM, ID_CMAP)) == NULL) {
  873.     fprintf (stderr, "%s: Missing BMHD or CMAP parsing %s\n", programname, fname);
  874.     partial_cleanup ();
  875.     return;
  876.   }
  877.  
  878.   bmhd = (struct BitMapHeader *)bmhdprop->sp_Data;
  879.  
  880.   width = bmhd->bmh_Width;
  881.   height = bmhd->bmh_Height;
  882.   depth = bmhd->bmh_Depth;
  883.   if ((camgprop = FindProp (iff, ID_ILBM, ID_CAMG)) != NULL)
  884.     intended_mode = *(ULONG *)camgprop->sp_Data;
  885.   else
  886.     intended_mode = 0;
  887.  
  888.   /* display file attributes */
  889.   printf ("\nFile = %s, size = %ld bytes\n", fname, fsize);
  890.   printf ("Anim size %ux%ux%u\n", width, height, depth);
  891.   printf ("Intended ModeID = %08lx", intended_mode);
  892.  
  893.   type_string = "";
  894.   propertymask = DIPF_IS_EXTRAHALFBRITE | DIPF_IS_DUALPF | DIPF_IS_PF2PRI |
  895.                  DIPF_IS_HAM;
  896.   if (camgprop != NULL &&
  897.       (*(ULONG *)camgprop->sp_Data & EXTRAHALFBRITE_KEY) != 0) {
  898.     printf ("  (EXTRAHALFBRITE)");
  899.     type_string = " EHB";
  900.     propertymask &= ~DIPF_IS_EXTRAHALFBRITE;
  901.   }
  902.   if (camgprop != NULL &&
  903.       (*(ULONG *)camgprop->sp_Data & HAM_KEY) != 0) {
  904.     switch (depth) {
  905.       case 6:
  906.         printf ("  (HAM)");
  907.         type_string = " HAM6";
  908.         break;
  909.       case 8:
  910.         printf ("  (HAM8)");
  911.         type_string = " HAM8";
  912.         break;
  913.       default:
  914.         die ("%s: HAM but not depth 6 or 8", programname);
  915.     }
  916.     propertymask &= ~DIPF_IS_HAM;
  917.   }
  918.   printf ("\n");
  919.  
  920.   first_time = TRUE;
  921.   warp_eclocks.ev_hi = 0;
  922.   warp_eclocks.ev_lo = 0;
  923.   eclocks.ev_hi = 0;
  924.   eclocks.ev_lo = 0;
  925.   total_eclocks.ev_hi = 0;
  926.   total_eclocks.ev_lo = 0;
  927.   if ((anhdprop = FindProp (iff, ID_ILBM, ID_ANHD)) != NULL) {
  928.     anhd = (struct AnimHeader *)anhdprop->sp_Data;
  929.     eclocks.ev_lo = (ULONG)((1000000.0 / 60.0) * anhd->anh_Reltime /
  930.                     micros_per_eclock + 0.5);
  931.     add64 (&total_eclocks, &eclocks);
  932.   }
  933.  
  934.   if (CyberGfxBase != NULL)
  935.     ti[0].ti_Data = BestCModeIDTags (CYBRBIDTG_NominalWidth, max(width, 320),
  936.                                      CYBRBIDTG_NominalHeight, max(height, 200),
  937.                                      CYBRBIDTG_Depth, max(depth, 4),
  938.                                      TAG_DONE);
  939.   else if (GfxBase->LibNode.lib_Version >= 39)
  940.     ti[0].ti_Data = BestModeID (BIDTAG_NominalWidth, width,
  941.                                 BIDTAG_NominalHeight, height,
  942.                                 BIDTAG_Depth, depth,
  943.                                 BIDTAG_DIPFMustNotHave, propertymask,
  944.                                 TAG_DONE);
  945.   else
  946.     ti[0].ti_Data = 0;
  947.   if (opt.modereq) {
  948.     sprintf (reqtitle, "%s %dx%d%s", programname, width, height, type_string);
  949.     if (!AslRequestTags (smr,
  950.                          ASLSM_TitleText,     (ULONG)reqtitle,
  951.                          ASLSM_InitialDisplayID, ti[0].ti_Data,
  952.                          ASLSM_MinWidth,      width,
  953.                          ASLSM_MinHeight,     height,
  954.                          ASLSM_MinDepth,      depth,
  955.                          ASLSM_MaxDepth,      8,
  956.                          ASLSM_PropertyMask,  propertymask,
  957.                          ASLSM_PropertyFlags, 0,
  958.                          TAG_DONE))
  959.       die ("%s: ScreenMode requester failed or cancelled", programname);
  960.     ti[0].ti_Data = smr->sm_DisplayID;
  961.   }
  962.  
  963.   printf ("Using ModeID = %08lx\n", ti[0].ti_Data);
  964.  
  965.   if ((count = GetDisplayInfoData (NULL, (UBYTE *)&dimsinfo,
  966.                                    sizeof(struct DimensionInfo), DTAG_DIMS,
  967.                                    ti[0].ti_Data)) < 66
  968.                                              /* sizeof(struct DimensionInfo) */)
  969.     die ("%s: GetDisplayInfoData(Dims) failed (%d)", programname, count);
  970.  
  971.   oscan_height = max(height, dimsinfo.MaxOScan.MaxY - dimsinfo.MaxOScan.MinY + 1);
  972.  
  973.   ns.Width = width;
  974.   nw.Width = width;
  975.   ns.Height = oscan_height << 1;
  976.   nw.Height = oscan_height << 1;
  977.   ns.Depth = max (depth, 4);
  978.   rect.MaxX = width - 1;
  979.   rect.MaxY = height - 1;
  980.  
  981.   if ((s = OpenScreen ((struct NewScreen *)&ns)) == NULL)
  982.     die ("%s: Can't open Screen", programname);
  983.  
  984.   load_cmap (s, (UBYTE *)cmapprop->sp_Data, 1 << depth, intended_mode);
  985.  
  986.   printf ("Screen size %ux%u\n", s->Width, s->Height >> 1);
  987.  
  988.   nw.Screen = s;
  989.   if ((w = OpenWindow (&nw)) == NULL)
  990.     die ("%s: Can't open Window", programname);
  991.  
  992.   emptypointer = (WORD *)AllocMem (12, MEMF_CHIP | MEMF_CLEAR);
  993.   SetPointer (w, emptypointer, 1, 16, 0, 0);
  994.  
  995.   for (i = 0; i < NBITMAPS; i++) {
  996.     if (CyberGfxBase != NULL && IsCyberModeID (GetVPModeID (&s->ViewPort))) {
  997.       using_fastmem_bitmap = TRUE;
  998.       using_intermediate_buffer = TRUE;
  999.       bm[i] = malloc_check (sizeof(struct BitMap));
  1000.       memset (bm[i], 0, sizeof(struct BitMap));
  1001.       InitBitMap (bm[i], depth, width, height);
  1002.       for (plane = 0; plane < bm[i]->Depth; plane++)
  1003.         bm[i]->Planes[plane] = malloc_check (bm[i]->BytesPerRow * bm[i]->Rows);
  1004.     } else if (GfxBase->LibNode.lib_Version >= 39 &&
  1005.                (GetBitMapAttr (s->ViewPort.RasInfo->BitMap, BMA_FLAGS) &
  1006.                                BMF_STANDARD) != 0 &&
  1007.                (GetBitMapAttr (s->ViewPort.RasInfo->BitMap, BMA_FLAGS) &
  1008.                                BMF_INTERLEAVED) == 0) {
  1009.       using_fastmem_bitmap = FALSE;
  1010.       using_intermediate_buffer = FALSE;
  1011.       bm[i] = malloc_check (sizeof(struct BitMap));
  1012.       memset (bm[i], 0, sizeof(struct BitMap));
  1013.       bm[i]->Rows = height;
  1014.       bm[i]->BytesPerRow = s->ViewPort.RasInfo->BitMap->BytesPerRow;
  1015.       bm[i]->Depth = s->ViewPort.RasInfo->BitMap->Depth;
  1016.       for (plane = 0; plane < bm[i]->Depth; plane++)
  1017.         bm[i]->Planes[plane] = &s->ViewPort.RasInfo->BitMap->Planes[plane]
  1018.                                 [i * bm[i]->BytesPerRow * oscan_height];
  1019.     } else {
  1020.       using_fastmem_bitmap = FALSE;
  1021.       using_intermediate_buffer = TRUE;
  1022.       if ((bm[i] = AllocBitMap (width, height, depth, 0, NULL)) == NULL)
  1023.         die ("%s: Can't allocate bitmap", programname);
  1024.     }
  1025.   }
  1026.   printf ("Bitmap size %ux%ux%u\n", bm[0]->BytesPerRow << 3,
  1027.           bm[0]->Rows, bm[0]->Depth);
  1028.   if (!using_fastmem_bitmap)
  1029.     printf ("Using CHIPMEM\n");
  1030.   if (!using_intermediate_buffer)
  1031.     printf ("Using direct rendering\n");
  1032.  
  1033.   dirty = (WORD *)malloc_check ((((bm[0]->BytesPerRow + 3) >> 2) << 1)
  1034.                                   * sizeof(WORD));
  1035.  
  1036.   /* PrintTopChunk (iff); */
  1037.  
  1038.   size = CurrentChunk (iff)->cn_Size;
  1039.   if (mystream->f != NULL) {
  1040.     body = (UBYTE *)malloc_check (size);
  1041.     if (ReadChunkBytes (iff, body, size) != size)
  1042.       die ("%s: Error reading %s", programname, fname);
  1043.   } else
  1044.     body = mystream->rambufptr;
  1045.  
  1046.   src = body;
  1047.   srcbytesperrow = RASSIZE (width, 1);
  1048.   for (plane = 0; plane < depth; plane++)
  1049.     dst[plane] = bm[0]->Planes[plane];
  1050.  
  1051.   for (y = 0; y < height; y++) {
  1052.     for (plane = 0; plane < depth; plane++) {
  1053.       switch (bmhd->bmh_Compression) {
  1054.         case cmpNone:
  1055.           memcpy (dst[plane], src, srcbytesperrow);
  1056.           src += srcbytesperrow;
  1057.           break;
  1058.         case cmpByteRun1:
  1059.           if (unpackrow ((BYTE **)&src, dst[plane], srcbytesperrow))
  1060.             die ("%s: Error unpacking BODY", programname);
  1061.           break;
  1062.         default:
  1063.           die ("%s: Unrecognised compression", programname);
  1064.       }
  1065.       dst[plane] += bm[0]->BytesPerRow;
  1066.     }
  1067.   }
  1068.  
  1069.   if (mystream->f != NULL)
  1070.     free (body);
  1071.  
  1072.   for (plane = 0; plane < depth; plane++)
  1073.     memcpy (bm[1]->Planes[plane], bm[0]->Planes[plane],
  1074.             bm[0]->BytesPerRow * bm[0]->Rows);
  1075.  
  1076.   if (using_intermediate_buffer) {
  1077.     BltBitMapRastPort (bm[0], 0, 0, w->RPort, 0, 0, width, height, 0xc0);
  1078.     BltBitMapRastPort (bm[1], 0, 0, w->RPort, 0, oscan_height, width, height,
  1079.                        0xc0);
  1080.   }
  1081.  
  1082.   /* read the start time */
  1083.   ReadEClock (time0);
  1084.   next_time = *time0;
  1085.   add64 (&next_time, &eclocks);
  1086.  
  1087.   which = 0;
  1088.   totalframes = 1;
  1089.   going = TRUE;
  1090.  
  1091.   while (going) {
  1092.  
  1093.     while ((msg = (struct IntuiMessage *)GetMsg (w->UserPort)) != NULL) {
  1094.       class = msg->Class;
  1095.       code = msg->Code;
  1096.       ReplyMsg ((struct Message *)msg);
  1097.       switch (class) {
  1098.         case IDCMP_VANILLAKEY:
  1099.           switch (code) {
  1100.             case 0x03: /* CTRL/C */
  1101.             case 0x1b: /* ESC */
  1102.             case 0x51: /* q */
  1103.             case 0x71: /* Q */
  1104.               going = FALSE;
  1105.               break;
  1106.             default:
  1107.               break;
  1108.           }
  1109.           break;
  1110.         case IDCMP_RAWKEY:
  1111.           switch (code) {
  1112.             case 0x50: /* F1 */
  1113.               warp_eclocks.ev_lo = 0;
  1114.               opt.warp = TRUE;
  1115.               break;
  1116.             case 0x51: /* F2 */
  1117.               warp_eclocks.ev_lo = (ULONG)((1000000.0 / 60.0) / micros_per_eclock + 0.5);
  1118.               opt.warp = TRUE;
  1119.               break;
  1120.             case 0x52: /* F3 */
  1121.               warp_eclocks.ev_lo = (ULONG)((1000000.0 / 30.0) / micros_per_eclock + 0.5);
  1122.               opt.warp = TRUE;
  1123.               break;
  1124.             case 0x53: /* F4 */
  1125.               warp_eclocks.ev_lo = (ULONG)((1000000.0 / 24.0) / micros_per_eclock + 0.5);
  1126.               opt.warp = TRUE;
  1127.               break;
  1128.             case 0x54: /* F5 */
  1129.               warp_eclocks.ev_lo = (ULONG)((1000000.0 / 15.0) / micros_per_eclock + 0.5);
  1130.               opt.warp = TRUE;
  1131.               break;
  1132.             case 0x55: /* F6 */
  1133.               warp_eclocks.ev_lo = (ULONG)((1000000.0 / 12.0) / micros_per_eclock + 0.5);
  1134.               opt.warp = TRUE;
  1135.               break;
  1136.             case 0x56: /* F7 */
  1137.               warp_eclocks.ev_lo = (ULONG)((1000000.0 / 10.0) / micros_per_eclock + 0.5);
  1138.               opt.warp = TRUE;
  1139.               break;
  1140.             case 0x57: /* F8 */
  1141.               warp_eclocks.ev_lo = (ULONG)((1000000.0 / 5.0) / micros_per_eclock + 0.5);
  1142.               opt.warp = TRUE;
  1143.               break;
  1144.             case 0x58: /* F9 */
  1145.               warp_eclocks.ev_lo = (ULONG)(1000000.0 / micros_per_eclock + 0.5);
  1146.               opt.warp = TRUE;
  1147.               break;
  1148.             case 0x59: /* F10 */
  1149.               opt.warp = FALSE;
  1150.               break;
  1151.             default:
  1152.               break;
  1153.           }
  1154.           break;
  1155.         case IDCMP_MOUSEBUTTONS:
  1156.           if (code == MENUDOWN)
  1157.             going = FALSE;
  1158.           break;
  1159.         default:
  1160.           break;
  1161.       }
  1162.     }
  1163.  
  1164. #ifdef __SASC
  1165.     chkabort ();
  1166. #endif
  1167.  
  1168.     /* PrintTopChunk (iff); */
  1169.  
  1170.     while ((ifferror = ParseIFF (iff, IFFPARSE_RAWSTEP)) == IFFERR_EOC)
  1171.       /* do nothing */ ;
  1172.  
  1173.     if (ifferror == IFFERR_EOF)
  1174.       if (opt.once)
  1175.         break;
  1176.       else {
  1177.         CloseIFF (iff);
  1178.         iff_is_open = FALSE;
  1179.         if (mystream->f != NULL)
  1180.           rewind (mystream->f);
  1181.         else if (mystream->rambuf != NULL)
  1182.           mystream->rambufptr = mystream->rambuf;
  1183.         else
  1184.           die ("%s: Internal error", programname);
  1185.         if (OpenIFF (iff, IFFF_READ) != 0)
  1186.           die ("%s: OpenIFF() failed", programname);
  1187.         iff_is_open = TRUE;
  1188.         if (StopChunk (iff, ID_ILBM, ID_BODY) != 0)
  1189.           die ("%s: Error calling StopChunk parsing %s", programname, fname);
  1190.         if ((ifferror = ParseIFF (iff, IFFPARSE_SCAN)) != 0)
  1191.           die ("%s: IFF error %d parsing %s for BODY", programname, ifferror, fname);
  1192.         while ((ifferror = ParseIFF (iff, IFFPARSE_RAWSTEP)) == IFFERR_EOC)
  1193.           /* do nothing */ ;
  1194.         if (StopChunk (iff, ID_ILBM, ID_DLTA) != 0)
  1195.           die ("%s: Error calling StopChunk parsing %s", programname, fname);
  1196.         if ((ifferror = ParseIFF (iff, IFFPARSE_SCAN)) != 0)
  1197.           if (ifferror != IFFERR_EOF)
  1198.             die ("%s: IFF error %d parsing %s for DLTA", programname, ifferror, fname);
  1199.           else {
  1200.             while (going) {
  1201.               sig = Wait ((1 << w->UserPort->mp_SigBit) | SIGBREAKF_CTRL_C);
  1202.               if ((sig & (1 << w->UserPort->mp_SigBit)) != 0) {
  1203.                 while ((msg = (struct IntuiMessage *)GetMsg (w->UserPort)) != NULL) {
  1204.                   class = msg->Class;
  1205.                   code = msg->Code;
  1206.                   ReplyMsg ((struct Message *)msg);
  1207.                   switch (class) {
  1208.                     case IDCMP_VANILLAKEY:
  1209.                       switch (code) {
  1210.                         case 0x03: /* CTRL/C */
  1211.                         case 0x1b: /* ESC */
  1212.                         case 0x51: /* q */
  1213.                         case 0x71: /* Q */
  1214.                           going = FALSE;
  1215.                           break;
  1216.                         default:
  1217.                           break;
  1218.                       }
  1219.                       break;
  1220.                     case IDCMP_MOUSEBUTTONS:
  1221.                       if (code == MENUDOWN)
  1222.                         going = FALSE;
  1223.                       break;
  1224.                     default:
  1225.                       break;
  1226.                   }
  1227.                 }
  1228.               }
  1229.               if ((sig & SIGBREAKF_CTRL_C) != 0)
  1230.                 going = FALSE;
  1231.             }
  1232.           }
  1233.         continue;
  1234.       }
  1235.     else if (ifferror != 0)
  1236.       die ("%s: IFF error %d parsing %s", programname, ifferror, fname);
  1237.  
  1238.     which = 1 - which;
  1239.  
  1240.     /* PrintTopChunk (iff); */
  1241.  
  1242.     if (PropChunk (iff, ID_ILBM, ID_ANHD) != 0 ||
  1243.         PropChunk (iff, ID_ILBM, ID_CMAP) != 0 ||
  1244.         StopChunk (iff, ID_ILBM, ID_DLTA) != 0)
  1245.       die ("%s: Error calling PropChunk or StopChunk parsing %s", programname, fname);
  1246.     if ((ifferror = ParseIFF (iff, IFFPARSE_SCAN)) != 0)
  1247.       die ("%s: IFF error %d parsing %s", programname, ifferror, fname);
  1248.     if ((anhdprop = FindProp (iff, ID_ILBM, ID_ANHD)) == NULL)
  1249.       die ("%s: missing ANHD chunk parsing %s", programname, fname);
  1250.  
  1251.     anhd = (struct AnimHeader *)anhdprop->sp_Data;
  1252.     eclocks.ev_lo = (ULONG)((1000000.0 / 60.0) * anhd->anh_Reltime /
  1253.                     micros_per_eclock + 0.5);
  1254.     add64 (&total_eclocks, &eclocks);
  1255.     if (first_time) {
  1256.       printf ("Anim type %d, abstime %ld, reltime, %ld, interleave %d, flags %08x\n",
  1257.               (int)anhd->anh_Operation, anhd->anh_Abstime, anhd->anh_Reltime,
  1258.               (int)anhd->anh_Interleave, anhd->anh_Bits);
  1259.       first_time = FALSE;
  1260.     }
  1261.  
  1262.     size = CurrentChunk (iff)->cn_Size;
  1263.     /* printf ("DLTA size %d at %d\n", size, CurrentChunk (iff)->cn_Scan); */
  1264.     if (mystream->f != NULL) {
  1265.       dlta = malloc_check (size);
  1266.       if (ReadChunkBytes (iff, dlta, size) != size)
  1267.         die ("%s: Error reading %s", programname, fname);
  1268.     } else
  1269.       dlta = mystream->rambufptr;
  1270.  
  1271.     if (using_intermediate_buffer)
  1272.       memset (dirty, -1, (((bm[0]->BytesPerRow + 3) >> 2) << 1) * sizeof(WORD));
  1273.     else
  1274.       if (opt.waittof)
  1275.         WaitTOF ();
  1276.  
  1277.     for (plane = 0; plane < depth; plane++) {
  1278.       wdata = (WORD *)&dlta[((ULONG *)dlta)[plane]];
  1279.       /* printf ("%d %08x %ld\n", plane, wdata, ((ULONG *)dlta)[plane]); */
  1280.  
  1281.       switch (anhd->anh_Operation) {
  1282.  
  1283.         case cmpLongdelta:    /* 2 */
  1284.           if (wdata != (WORD *)dlta)
  1285.             unpacklongdelta (wdata, (LONG *)bm[which]->Planes[plane],
  1286.                              bm[which]->BytesPerRow, dirty);
  1287.           break;
  1288.  
  1289.         case cmpShortdelta:    /* 3 */
  1290.           if (wdata != (WORD *)dlta)
  1291.             unpackshortdelta (wdata, (WORD *)bm[which]->Planes[plane],
  1292.                              bm[which]->BytesPerRow, dirty);
  1293.           break;
  1294.  
  1295.         case cmpBytedelta:    /* 5 */
  1296.           if (wdata != (WORD *)dlta)
  1297.             if (using_intermediate_buffer)
  1298.               unpackbytedelta ((BYTE *)wdata, bm[which]->Planes[plane],
  1299.                                bm[which]->BytesPerRow, dirty);
  1300.             else
  1301.               unpackbytedeltanodirty ((BYTE *)wdata, bm[which]->Planes[plane],
  1302.                                       bm[which]->BytesPerRow);
  1303.           break;
  1304.  
  1305.         case cmpAnim7:        /* 7 */
  1306.           if (wdata != (WORD *)dlta)
  1307.             if ((anhd->anh_Bits & 1) != 0)
  1308.               if (using_intermediate_buffer)
  1309.                 unpackanim7long ((BYTE *)wdata,
  1310.                                  (LONG *)&dlta[((ULONG *)dlta)[plane + 8]],
  1311.                                  bm[which]->Planes[plane],
  1312.                                  bm[which]->BytesPerRow,
  1313.                                  dirty);
  1314.               else
  1315.                 unpackanim7longnodirty ((BYTE *)wdata,
  1316.                                         (LONG *)&dlta[((ULONG *)dlta)[plane + 8]],
  1317.                                         bm[which]->Planes[plane],
  1318.                                         bm[which]->BytesPerRow);
  1319.             else
  1320.               unpackanim7word ((BYTE *)wdata,
  1321.                                (WORD *)&dlta[((ULONG *)dlta)[plane + 8]],
  1322.                                bm[which]->Planes[plane],
  1323.                                bm[which]->BytesPerRow >> 1,
  1324.                                dirty);
  1325.           break;
  1326.  
  1327.         case cmpDirect:        /* 0 */
  1328.         case cmpXor:        /* 1 */
  1329.         case cmpDelta:        /* 4 */
  1330.         case cmpStereo:        /* 6 */
  1331.         case cmpJ:        /* 74 */
  1332.         default:
  1333.           die ("%s: Anim type %d not recognised", programname,
  1334.                     (int)anhd->anh_Operation);
  1335.       }
  1336.     }
  1337.  
  1338.     if (mystream->f != NULL)
  1339.       free (dlta);
  1340.  
  1341.     if (using_intermediate_buffer) {
  1342.  
  1343.       /* need to wait for cybergraphics TOF to avoid flicker here, but HOW????
  1344.          WaitTOF() appears to wait for custom chips which are different
  1345.          frequency and phase to cybergraphics display.  */
  1346.       if (opt.waittof)
  1347.         WaitTOF ();
  1348.  
  1349.       if (anhd->anh_Operation == cmpBytedelta ||
  1350.           anhd->anh_Operation == cmpAnim7)
  1351.         blit_opt (bm[which], w->RPort, dirty, which != 0 ? oscan_height : 0);
  1352.       else
  1353.         BltBitMapRastPort (bm[which], 0, 0, w->RPort, 0,
  1354.                            which != 0 ? oscan_height : 0, width, height, 0xc0);
  1355.     }
  1356.  
  1357.     /* wait for time between frames */
  1358.     delay_until (&next_time);
  1359.     if (opt.warp)
  1360.       add64 (&next_time, &warp_eclocks);
  1361.     else
  1362.       add64 (&next_time, &eclocks);
  1363.  
  1364.     if ((cmapprop = FindProp (iff, ID_ILBM, ID_CMAP)) != NULL)
  1365.       load_cmap (s, (UBYTE *)cmapprop->sp_Data, 1 << depth, intended_mode);
  1366.  
  1367.     /* MoveScreen (s, which != 0 ? oscan_height : -oscan_height, 0); */
  1368.  
  1369.     if (which != 0)
  1370.       s->ViewPort.RasInfo->RyOffset += oscan_height;
  1371.     else
  1372.       s->ViewPort.RasInfo->RyOffset -= oscan_height;
  1373.     ScrollVPort (&s->ViewPort);
  1374.  
  1375.     totalframes++;
  1376.   }
  1377.  
  1378.   /* find out and display how long it took */
  1379.   ReadEClock (time1);
  1380.   if (total_eclocks.ev_hi != 0 || total_eclocks.ev_lo != 0)
  1381.     printf ("%s: Intended frames per second = %4.1lf\n", programname,
  1382.             1000000.0 * totalframes /
  1383.             ((total_eclocks.ev_hi * 4294967296.0 + total_eclocks.ev_lo) *
  1384.              micros_per_eclock));
  1385.   sub64 (time1, time0);
  1386.   printf ("%s: Achieved frames per second = %4.1lf\n", programname,
  1387.           1000000.0 * totalframes /
  1388.           ((time1->ev_hi * 4294967296.0 + time1->ev_lo) * micros_per_eclock));
  1389.  
  1390.   partial_cleanup ();
  1391. }
  1392.  
  1393. /****************************************************************************/
  1394.  
  1395. static void filerequestloop (struct options *opt)
  1396. {
  1397.   static char resultstring[128];
  1398.  
  1399.   if (AslBase != NULL) {
  1400.     while (AslRequest (fr, NULL)) {
  1401.       strcpy (resultstring, fr->rf_Dir);
  1402.       AddPart (resultstring, fr->rf_File, 128);
  1403.       animate_file (resultstring, *opt);
  1404.     }
  1405.   }
  1406. }
  1407.  
  1408. /****************************************************************************/
  1409.  
  1410. static LONG argarray[16] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
  1411.  
  1412. int main (int argc, char *argv[])
  1413. {
  1414.   struct WBStartup *argmsg;
  1415.   struct WBArg *wb_arg;
  1416.   char **fnames;
  1417.   UWORD ktr;
  1418.   struct options opt;
  1419.  
  1420.   if (atexit (cleanup) != 0)
  1421.     die ("Can't install exit handler");
  1422.  
  1423.   GetProgramName (programname, 19);
  1424.  
  1425.   CyberGfxBase = OpenLibrary ("cybergraphics.library", 0);
  1426.  
  1427.   if ((IFFParseBase = OpenLibrary ("iffparse.library", 0)) == NULL)
  1428.     die ("%s: Can't open iff.library", programname);
  1429.  
  1430.   if ((AslBase = (struct Library *)OpenLibrary ("asl.library", 38L)) == NULL)
  1431.     die ("%s: Can't open asl.library v38", programname);
  1432.  
  1433.   if ((fr = (struct FileRequester *)AllocAslRequestTags (ASL_FileRequest,
  1434.            ASL_Hail,           (ULONG)programname,
  1435.            ASL_Pattern,        (ULONG)"~(#?.info)",
  1436.            ASL_OKText,         (ULONG)"Play",
  1437.            ASL_CancelText,     (ULONG)"Cancel",
  1438.            ASL_FuncFlags,      FILF_PATGAD,
  1439.            TAG_DONE)) == NULL)
  1440.     die ("%s: Can't allocate file requester\n", programname);
  1441.  
  1442.   if ((smr = AllocAslRequestTags (ASL_ScreenModeRequest, TAG_DONE)) == NULL)
  1443.     die ("%s: Can't allocate screenmode requester\n", programname);
  1444.  
  1445.   /* timer stuff */
  1446.   if ((timermp = CreatePort (0, 0)) == NULL)
  1447.     die ("%s: Can't create messageport!", programname);
  1448.   if ((timerio = (struct timerequest *)CreateExtIO (timermp,
  1449.                  sizeof(struct timerequest))) == NULL)
  1450.     die ("%s: Can't create External IO!", programname);
  1451.   if (timerclosed = OpenDevice (TIMERNAME, UNIT_MICROHZ,
  1452.                                 (struct IORequest *)timerio, 0))
  1453.     die ("%s: Can't open timer.device!", programname);
  1454.   TimerBase = (struct Library *)timerio->tr_node.io_Device;
  1455.   if ((time = (struct EClockVal *)AllocMem (sizeof(struct EClockVal),
  1456.                                           MEMF_CLEAR | MEMF_PUBLIC)) == NULL ||
  1457.       (time0 = (struct EClockVal *)AllocMem (sizeof(struct EClockVal),
  1458.                                           MEMF_CLEAR | MEMF_PUBLIC)) == NULL ||
  1459.       (time1 = (struct EClockVal *)AllocMem (sizeof(struct EClockVal),
  1460.                                           MEMF_CLEAR | MEMF_PUBLIC)) == NULL)
  1461.     die ("%s: Out of memory", programname);
  1462.   micros_per_eclock = 1000000.0 / (double)ReadEClock (time);
  1463.  
  1464.   opt.ram = TRUE;
  1465.   opt.once = FALSE;
  1466.   opt.dbuf = TRUE;
  1467.   opt.warp = FALSE;
  1468.   opt.modereq = TRUE;
  1469.   opt.waittof = FALSE;
  1470.  
  1471.   /* parse workbench message or commandline */
  1472.   if (argc == 0) {
  1473.     argmsg = (struct WBStartup *)argv;
  1474.     wb_arg = argmsg->sm_ArgList;
  1475.     strcpy (programname, wb_arg->wa_Name);
  1476.     parse_tooltypes (wb_arg->wa_Name, &opt);
  1477.     if (argmsg->sm_NumArgs <= 1)
  1478.       filerequestloop (&opt);
  1479.     else {
  1480.       wb_arg++;
  1481.       for (ktr = 1; ktr < argmsg->sm_NumArgs; ktr++, wb_arg++)
  1482.         if (wb_arg->wa_Lock != NULL) {
  1483.           olddir = CurrentDir (wb_arg->wa_Lock);
  1484.           animate_file (wb_arg->wa_Name, opt);
  1485.           CurrentDir (olddir);
  1486.           olddir = NULL;
  1487.         } else
  1488.           animate_file (wb_arg->wa_Name, opt);
  1489.       }
  1490.   } else {
  1491.     if ((rdargs = ReadArgs
  1492.         ("FILE/M,DISK/S,RAM/S,ONCE/S,WARP/S,NOMODEREQ/S,WAITTOF/S", argarray,
  1493.          NULL)) != NULL) {
  1494.       if (argarray[1])
  1495.         opt.ram = FALSE;
  1496.       if (argarray[2])
  1497.         opt.ram = TRUE;
  1498.       if (argarray[3])
  1499.         opt.once = TRUE;
  1500.       if (argarray[4])
  1501.         opt.warp = TRUE;
  1502.       if (argarray[5])
  1503.         opt.modereq = FALSE;
  1504.       if (argarray[6])
  1505.         opt.waittof = TRUE;
  1506.       fnames = (char **)argarray[0];
  1507.       if (fnames == NULL || *fnames == NULL)
  1508.         filerequestloop (&opt);
  1509.       else
  1510.         while (*fnames != NULL)
  1511.           animate_file (*fnames++, opt);
  1512.       FreeArgs (rdargs);
  1513.       rdargs = NULL;
  1514.     }
  1515.   }
  1516.  
  1517.   return (0);
  1518. }
  1519.  
  1520. /****************************************************************************/
  1521.